// run: $exec < input
#include <iostream>
#include <vector>
#include <limits>
#include <queue>

template <class T>
struct dinic
{
	typedef T value_type;
	typedef int size_type;
	typedef std::vector<size_type>::iterator edge_iter;

	struct edge {
		size_type from, to;
		value_type capacity, flow;
	};

	dinic(size_type num) : size(num)
	{
		graph.resize(num);	//[0, num)
		dist.resize(num);	//[0, num)
	}

	void add_edge(int u, int v, value_type cap = capacity_inf)
	{
		edge tmp;
		tmp.from = u; tmp.to = v; tmp.capacity = cap; tmp.flow = 0;
		edges.push_back(tmp);
		graph[u].push_back(edges.size() - 1);

		tmp.from = v; tmp.to = u; tmp.capacity = 0; tmp.flow = 0;
		edges.push_back(tmp);
		graph[v].push_back(edges.size() - 1);
	}

	bool bfs_label(size_type source, size_type target)
	{
		std::fill(dist.begin(), dist.end(), -1);
		std::queue<size_type> q;
		q.push(source);
		dist[source] = 0;
		while (!q.empty()) {
			size_type now = q.front();
			q.pop();
			for (edge_iter it = graph[now].begin(); it != graph[now].end(); ++it) {
				edge e = edges[*it];
				if (dist[e.to] == -1 && e.capacity > e.flow) {
					q.push(e.to);
					dist[e.to] = dist[now] + 1;
				}
			}
		}
		return dist[target] != -1;
	}

	value_type dfs(size_type v, size_type target, value_type f)
	{
		if (v == target || !f) return f;
		value_type block_flow = 0;
		for (edge_iter it = graph[v].begin(); it != graph[v].end(); ++it) {
			edge & e = edges[*it];
			if (e.capacity > e.flow && dist[e.to] == dist[v] + 1) {
				value_type tmp = dfs(e.to, target,
						std::min(e.capacity - e.flow, f - block_flow));
				block_flow += tmp;
				e.flow += tmp;
				edges[(*it) ^ 1].flow -= tmp;
			}
		}
		if (!block_flow) dist[v] = -1;
		return block_flow;
	}

	value_type max_flow(size_type source, size_type target)
	{
		value_type flow = 0;
		for (int tmp; bfs_label(source, target); )
			while ((tmp = dfs(source, target, capacity_inf))) flow += tmp;
		return flow;
	}

//private:
	value_type static const capacity_inf = std::numeric_limits<value_type>::max();
	size_type size;
	std::vector<int> dist;
	std::vector<edge> edges;
	std::vector<std::vector<size_type>> graph;
};

int const max_num = 21000;
int const maxn = 207;
bool not_prime[max_num];
int da[maxn];
int n;

void init_prime()
{
	not_prime[0] = not_prime[1] = true;
	for (int i = 2; i < max_num; i++)
		if (!not_prime[i])
			for (int j = i * 2; j < max_num; j += i) not_prime[j] = true;
}

bool vis[maxn];

std::vector<std::vector<int>> ans;
dinic<int> d(2*maxn + 1);
int s, t;

bool map[maxn][maxn];

void init_map()
{
	auto & edges = d.edges;
	for (auto it = edges.begin(); it != edges.end(); ++it)
		if (it->flow == 1)
			map[it->from][it->to] = map[it->to][it->from] = true;
}

void dfs(int x, std::vector<int> & v)
{
	vis[x] = true;
	v.push_back(x);
	for (int i = 1; i <= n; i++)
		if (map[x][i] && !vis[i])
			dfs(i, v);
}

int main()
{
	std::ios::sync_with_stdio(false);
	init_prime();
	std::cin >> n;
	for (int i = 0; i < n; i++) std::cin >> da[i];

	s = 0; t = n + 1;
	int count = 0;
	for (int i = 0; i < n; i++) {
		count += !(da[i] & 1);
		if (da[i] & 1)
			d.add_edge(s, i + 1, 2);
		else
			d.add_edge(i + 1, t, 2);
		for (int j = i + 1; j < n; j++) {
			if (not_prime[da[i] + da[j]]) continue;
			if (da[i] & 1)
				d.add_edge(i + 1, j + 1, 1);
			else
				d.add_edge(j + 1, i + 1, 1);
		}
	}

	int max_flow = d.max_flow(s, t);
//	std::cerr << "max flow = " << max_flow << '\n';
	if (max_flow != 2 * count || count != n - count) {
		std::cout << "Impossible\n";
		return 0;
	}

	init_map();

	for (int i = 1; i <= n; i++)
		if (!vis[i]) {
			std::vector<int> v;
			dfs(i, v);
			ans.push_back(v);
		}

	std::cout << ans.size() << '\n';
	for (auto i : ans) {
		std::cout << i.size();
		for (auto j : i) std::cout << ' ' << j;
		std::cout << '\n';
	}
}

